/**
 * File: FastBlockWriter.java
 * Created by: mhaimel
 * Created on: Jun 23, 2011
 * CVS:  $Id: FastBlockWriter.java 1.0 Jun 23, 2011 1:50:41 PM mhaimel Exp $
 */
package uk.ac.ebi.curtain.storage.sequence.fast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.io.output.CountingOutputStream;

import uk.ac.ebi.curtain.storage.CompressorStrategy;
import uk.ac.ebi.curtain.storage.GzipFormatCompressor;
import uk.ac.ebi.curtain.storage.sequence.PositionAwareStream;

/**
 * @author mhaimel
 *
 */
public class FastBlockWriter extends Writer implements PositionAwareStream{
	private final CountingOutputStream oCnt;
	private final AtomicLong unbufferedCount = new AtomicLong(0l);
	private final CompressorStrategy strategy;

	
	public FastBlockWriter(File f, boolean append) throws FileNotFoundException {
		this(f,append,getDefaultStrategy());
	}

	public static GzipFormatCompressor getDefaultStrategy() {
		return new GzipFormatCompressor(0, 5);
	}
	
	public FastBlockWriter(File f, boolean append, CompressorStrategy strategy) throws FileNotFoundException {
		this(new FileOutputStream(f,append),strategy);
	}

	public FastBlockWriter(OutputStream out, CompressorStrategy strategy) throws FileNotFoundException {
		this.oCnt = new CountingOutputStream(out);
		this.strategy = strategy;
	}

	
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void close() throws IOException {
		this.oCnt.close();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void flush() throws IOException {
		this.oCnt.flush();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void write(char[] cbuf, int off, int len) throws IOException {
		if(len <= 0){
			return;
		}
		byte[] barr = new byte[len];
		int i = 0;
		while(i<len){
			barr[i] = (byte) cbuf[off+i];
			++i;
		}
		byte[] compressed = _doCompress(barr);
		this.oCnt.write(compressed);
		this.writeEvent(unbufferedCount.addAndGet(len), this.getCount());
	}

	private byte[] _doCompress(byte[] barr) {
		return getStrategy().compressBytes(barr);
	}

	protected CompressorStrategy getStrategy() {
		return strategy;
	}
	
	protected void writeEvent(long uncomp, long comp) {
		// do nothing
	}

	public long getUnbufferedCount() {
		return unbufferedCount.get();
	}

	@Override
	public long getCount() {
		return this.oCnt.getByteCount();
	}

	@Override
	public long resetCount() {
		return this.oCnt.resetByteCount();
	}
}
